#pragma once
#include <iostream>
#include <queue>
#include <unistd.h>
#include <pthread.h>
#include "Mutex.hpp"
#include "Cond.hpp"
using namespace std;
using namespace MutexModule;
using namespace CondModule;

namespace BlockQueueModule
{
    // verson2:
    static int gcap = 10;
    template <typename T>
    class BlockQueue
    {
    private:
        bool isFull()
        {
            return _q.size() == _cap;
        }
        bool isEmpty()
        {
            return _q.empty();
        }

    public:
        BlockQueue(int cap = gcap)
            : _cap(cap), _cwait_num(0), _pwait_num(0)
        {}
        ~BlockQueue()
        {}
        void Enqueue(const T &in)
        {
            LockGuard lock(_mutex);
            while (isFull()) // 满了此时不能放数据应该在条件变量等待
            {
                cout << "生产者进入等待..." << endl;
                _pwait_num++;         // 等待线程++
                _p_cond.Wait(_mutex); // 等待
                _pwait_num--;         // 等待线程--
                cout << "生产者被唤醒..." << endl;
            }
            // if条件不满足 || 线程被唤醒
            _q.push(in); // 生产
            // 走到这一定有一个数据
            if (_cwait_num)
            {
                cout << "叫醒消费者.." << endl;
                _c_cond.Notify(); // 唤醒消费者
            }
        }
        void Pop(T *out)
        {
            LockGuard lock(_mutex);
            while (isEmpty())
            {
                cout << "消费者进入等待..." << endl;
                _cwait_num++;
                _c_cond.Wait(_mutex);
                _cwait_num--;
                cout << "消费者被唤醒..." << endl;
            }
            // 队列不为空 ||  线程被唤醒
            *out = _q.front(); // 消费
            _q.pop();
            // 走到这一定有空间
            if (_pwait_num)
            {
                cout << "叫醒生产者.." << endl;
                _p_cond.Notify(); // 唤醒生产者
            }
        }

    private:
        queue<T> _q;  // 保存数据容器
        int _cap;     // bq最大容量
        Mutex _mutex; // 锁保证互斥 单生产单消费一把锁
        // 一个条件变量无法区分等的是c还是p
        Cond _p_cond;   // 生产者条件变量
        Cond _c_cond;   // 消费者条件变量
        int _cwait_num; // 消费者等待个数
        int _pwait_num; // 生成者等待个数
    };

    // verson1
    //  static int gcap = 10;
    //  template <typename T>
    //  class BlockQueue
    //  {
    //  private:
    //      bool isFull()
    //      {
    //          return _q.size() == _cap;
    //      }
    //      bool isEmpty()
    //      {
    //          return _q.empty();
    //      }

    // public:
    //     BlockQueue(int cap = gcap)
    //         : _cap(cap), _cwait_num(0), _pwait_num(0)
    //     {
    //         pthread_mutex_init(&_mutex, nullptr);
    //         pthread_cond_init(&_p_cond, nullptr);
    //         pthread_cond_init(&_c_cond, nullptr);
    //     }
    //     ~BlockQueue()
    //     {
    //         pthread_mutex_destroy(&_mutex);
    //         pthread_cond_destroy(&_p_cond);
    //         pthread_cond_destroy(&_c_cond);
    //     }
    //     void Enqueue(const T &in)
    //     {
    //         pthread_mutex_lock(&_mutex);
    //         while(isFull()) // 满了此时不能放数据应该在条件变量等待
    //         {
    //             cout << "生产者进入等待..." << endl;
    //             _pwait_num++; // 等待线程++
    //             pthread_cond_wait(&_p_cond, &_mutex);
    //             _pwait_num--; // 等待线程--
    //             cout << "生产者被唤醒..." << endl;
    //         }
    //         // if条件不满足 || 线程被唤醒
    //         _q.push(in); // 生产
    //         //走到这一定有一个数据
    //         if(_cwait_num)
    //         {
    //             cout << "叫醒消费者.." << endl;
    //             pthread_cond_signal(&_c_cond); //唤醒消费者
    //         }
    //         pthread_mutex_unlock(&_mutex);
    //     }
    //     void Pop(T *out)
    //     {
    //         pthread_mutex_lock(&_mutex);
    //         while (isEmpty())
    //         {
    //             cout << "消费者进入等待..." << endl;
    //             _cwait_num++;
    //             pthread_cond_wait(&_c_cond, &_mutex);
    //             _cwait_num--;
    //             cout << "消费者被唤醒..." << endl;
    //         }
    //         // 队列不为空 ||  线程被唤醒
    //         *out = _q.front(); // 消费
    //         _q.pop();
    //         //走到这一定有空间
    //         if(_pwait_num)
    //         {
    //             cout << "叫醒生产者.." << endl;
    //             pthread_cond_signal(&_p_cond); //唤醒生产者
    //         }
    //         pthread_mutex_unlock(&_mutex);
    //     }

    // private:
    //     queue<T> _q;      // 保存数据容器
    //     int _cap;         // bq最大容量
    //     pthread_mutex_t _mutex; // 锁保证互斥 单生产单消费一把锁
    //     // 一个条件变量无法区分等的是c还是p
    //     pthread_cond_t _p_cond; // 生产者条件变量
    //     pthread_cond_t _c_cond; // 消费者条件变量
    //     int _cwait_num;         // 消费者等待个数
    //     int _pwait_num;         // 生成者等待个数
    // };

}
